﻿using System;
using System.Collections.Generic;
using System.Linq;
using Opo.Net.Mail;
using Opo.Net.Mime;
using Ninject.Core;

namespace Opo.Perspective.Core
{
    /// <summary>
    /// Represents a facade for a POP3 mail server
    /// </summary>
    public class Pop3MailStore : IMailStore
    {
        IPop3Client _mailClient;
        IMimeParser _mimeParser;
        IMailMessageConverter _converter;

        /// <summary>
        /// Gets or sets the host for the POP3 client.
        /// </summary>
        /// <value>The host for the POP3 client.</value>
        public string Host
        {
            get
            {
                return _mailClient.Host;
            }
            set
            {
                _mailClient.Host = value;
            }
        }
        /// <summary>
        /// Gets or sets the port for the POP3 client.
        /// </summary>
        /// <value>The port for the POP3 client.</value>
        public int Port
        {
            get
            {
                return _mailClient.Port;
            }
            set
            {
                _mailClient.Port = value;
            }
        }
        /// <summary>
        /// Gets or sets the username for the authentication on the POP3 client.
        /// </summary>
        /// <value>The username for the authentication on the POP3 client.</value>
        public string Username
        {
            get
            {
                return _mailClient.Username;
            }
            set
            {
                _mailClient.Username = value;
            }
        }
        /// <summary>
        /// Gets or sets the password for the authentication on the POP3 client.
        /// </summary>
        /// <value>The password for the authentication on the POP3 client.</value>
        public string Password
        {
            get
            {
                return _mailClient.Password;
            }
            set
            {
                _mailClient.Password = value;
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Pop3MailStore"/> class.
        /// </summary>
        /// <param name="mailClient">An instance of a POP3 IRecieveMailClient.</param>
        /// <param name="mimeParser">The MIME parser that is used to parse the mail messages.</param>
        public Pop3MailStore(IPop3Client mailClient, IMimeParser mimeParser)
        {
            if (mailClient == null)
            {
                throw new ArgumentNullException("mailClient");
            }
            if (mimeParser == null)
            {
                throw new ArgumentNullException("mimeParser");
            }
            _mailClient = mailClient;
            _mimeParser = mimeParser;
            _converter = new MimeMailMessageConverter(_mimeParser);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Pop3MailStore"/> class.
        /// </summary>
        /// <param name="mailClient">An instance of a POP3 IRecieveMailClient</param>
        /// <param name="mimeParser">The MIME parser that is used to parse the mail messages</param>
        /// <param name="host">Host of the mail client</param>
        /// <param name="port">Port of the mail client</param>
        /// <param name="username">The username for the authentication on the mail server</param>
        /// <param name="password">The password for the authentication on the mail server</param>
        public Pop3MailStore(IPop3Client mailClient, IMimeParser mimeParser, string host, int port, string username, string password)
            : this(mailClient, mimeParser)
        {
            Host = host;
            Port = port;
            Username = username;
            Password = password;
        }

        /// <summary>
        /// Gets a message.
        /// </summary>
        /// <param name="id">The id of the message (Message-ID)</param>
        /// <returns></returns>
        public IMailMessage GetMessage(string id)
        {
            _mailClient.Connect();
            _mailClient.Login();
            string mimeData = _mailClient.GetMessage(id);
            _mailClient.Logout();
            _mailClient.Disconnect();
            IMailMessage message = _converter.ConvertFrom(mimeData);

            return message;

        }
        /// <summary>
        /// Get all messages from the mail server.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<IMailMessage> GetMessages()
        {
            List<IMailMessage> messages = new List<IMailMessage>();

            _mailClient.Connect();
            _mailClient.Login();
            for (int i = 0; i < _mailClient.Mailbox.NumberOfMessages; i++)
            {
                string mimeData = _mailClient.GetMessage(i);
                IMailMessage message = _converter.ConvertFrom(mimeData);
                messages.Add(message);
            }
            _mailClient.Logout();
            _mailClient.Disconnect();
            return messages;
        }
        /// <summary>
        /// Gets only the new messages on the server.
        /// </summary>
        /// <param name="excludeMessageIDs">A list of Message-IDs to exclude.</param>
        /// <returns></returns>
        public IEnumerable<IMailMessage> GetNewMessages(IEnumerable<string> excludeMessageIDs)
        {
            IDictionary<int, string> headers = new Dictionary<int, string>();
            List<int> messageNumbers = new List<int>();
            List<IMailMessage> messages = new List<IMailMessage>();
            
            _mailClient.Connect();
            _mailClient.Login();

            for (int i = 0; i < _mailClient.Mailbox.NumberOfMessages; i++)
            {
                string messageID = _mimeParser.ParseHeaderValue(_mailClient.GetMessageHeaders(i), "Message-ID");
                headers.Add(i, messageID);
            }
            messageNumbers = (from n in headers
                              where excludeMessageIDs.Contains(n.Value)
                              select n.Key).ToList();

            foreach (int messageNumber in messageNumbers)
            {
                string mimeData = _mailClient.GetMessage(messageNumber);
                IMailMessage message = _converter.ConvertFrom(mimeData);
                messages.Add(message);
            }

            _mailClient.Logout();
            _mailClient.Disconnect();

            return messages;
        }
    }
}
